﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using nanoCMS.Core;
using nanoCMS.Forum.Concrete;

namespace nanoCMS.Forum.Providers
{
    public class ThreadProvider
    {
        private readonly WorldContext worldContext;
        private ForumEntities _entities; //DO NOT ACCESS DIRECTLY
        private ForumEntities Entities
        {
            get { return _entities ?? (_entities = new ForumEntities(worldContext.EntityConnectionString)); }
        }


        public ThreadProvider(WorldContext worldContext)
        {
            this.worldContext = worldContext;
        }

        public Thread GetThread(int threadID)
        {
            return Entities.Threads.Where(t => t.ThreadID == threadID).SingleOrDefault(); 
        }

        public Thread GetThreadByThreadPostID(int postID)
        {
            return Entities.Threads.Where(t => t.ThreadPostID == postID).SingleOrDefault();
        }

        public List<Thread> GetThreads(int forumId)
        {
            return Entities.Threads.Where(t => t.ForumID == forumId).ToList(); 
        }

        public List<Thread> GetForumThreads (int forumID, int page, int postsPerPage)
        {
            return Entities.Threads.Where(t => t.ForumID == forumID).OrderByDescending(t => t.LastPostTime).Skip(
                page * postsPerPage).Take(postsPerPage).ToList();
        }
        public Thread CreateThread(int userID, int forumID, string threadTitle, string threadDescription, 
            string postTitle, string postContent, DateTime postTime)
        {
            // update forum thread count
            Concrete.Forum forum = Entities.Forums.Where(f => f.ForumID == forumID).SingleOrDefault(); 
            if(forum == null)
            {
                throw new Exception(String.Format("No forum with ForumID = {0}.", forumID));
            }
            forum.ThreadsCount++;
            Entities.ObjectStateManager.ChangeObjectState(forum, EntityState.Modified);
            Thread newThread = new Thread
            {
                Title = threadTitle,
                Description = threadDescription,
                ForumID = forumID,
                ThreadUserID = userID, 
                ViewsCount = 0,
                PostsCount = 0
            };
            // create new post - ThreadID = null ==> doesn't count as real post, "ThreadPost"
            Post newPost = new Post
            {
                Title = postTitle,
                Content = postContent,
                PostTime = postTime,
                UserID = userID,
            };
            // bind thread & post
            newThread.Post = newPost;
            Entities.Threads.AddObject(newThread);
            Entities.SaveChanges(); 
            // return thread object
            return newThread; 
        }

        public void IncreaseThreadPostCount(int threadID)
        {
            // update thread posts
            Thread thread = Entities.Threads.Where(t => t.ThreadID == threadID).SingleOrDefault();
            if (thread == null)
            {
                throw new Exception(String.Format("No thread with ThreadID = {0}.", threadID));
            }
            thread.PostsCount++;
            thread.LastPostTime = DateTime.Now;
            Entities.ObjectStateManager.ChangeObjectState(thread, EntityState.Modified);
            Entities.SaveChanges(); 
        }

        public void DecreaseThreadPostCount(int threadID)
        {
            // update thread posts
            Thread thread = Entities.Threads.Where(t => t.ThreadID == threadID).SingleOrDefault();
            if (thread == null)
            {
                throw new Exception(String.Format("No thread with ThreadID = {0}.", threadID));
            }
            thread.PostsCount = thread.PostsCount == 0 ? 0 : thread.PostsCount - 1; // always > 0
            Entities.ObjectStateManager.ChangeObjectState(thread, EntityState.Modified);
            Entities.SaveChanges();
        }

        public void IncreaseThreadViews(int threadID)
        {
            // update thread posts
            Thread thread = Entities.Threads.Where(t => t.ThreadID == threadID).SingleOrDefault();
            if (thread == null)
            {
                throw new Exception(String.Format("No thread with ThreadID = {0}.", threadID));
            }
            thread.ViewsCount++;
            Entities.ObjectStateManager.ChangeObjectState(thread, EntityState.Modified);
            Entities.SaveChanges();
        }

        public void DeleteThread(int threadID)
        {
            Thread thread = GetThread(threadID);
            Entities.DeleteObject(thread);
            Entities.SaveChanges(); 
        }

        public Thread EditThread(int threadID, string threadTitle, string threadDescription,
            string postTitle, string postContent)
        {
            Thread thread = Entities.Threads.Where(t => t.ThreadID == threadID).SingleOrDefault();
            if(thread != null)
            {
                // update thread data
                thread.Title = threadTitle;
                thread.Description = threadDescription; 
                // update thread post data // TODO check existance
                Post post = Entities.Posts.Where(p => p.PostID == thread.ThreadPostID.Value).SingleOrDefault();
                post.Title = postTitle;
                post.Content = postContent; 
                // update new data
                Entities.ObjectStateManager.ChangeObjectState(thread, EntityState.Modified);
                Entities.ObjectStateManager.ChangeObjectState(post, EntityState.Modified);
                Entities.SaveChanges(); 
            }
            return thread; 
        }

        public void MoveThread(int threadID, int forumID)
        {
            Thread thread = GetThread(threadID); 
            if(thread != null)
            {
                // update thread forum 
                thread.ForumID = forumID; 
            }
            Entities.ObjectStateManager.ChangeObjectState(thread, EntityState.Modified);
            Entities.SaveChanges(); 
        }

        public void LockThread(int threadID)
        {
            Thread thread = GetThread(threadID);
            if (thread != null)
            {
                // update thread forum 
                thread.IsClosed = true; 
            }
            Entities.ObjectStateManager.ChangeObjectState(thread, EntityState.Modified);
            Entities.SaveChanges(); 
        }

        public void UnlockThread(int threadID)
        {
            Thread thread = GetThread(threadID);
            if (thread != null)
            {
                // update thread forum 
                thread.IsClosed = false;
            }
            Entities.ObjectStateManager.ChangeObjectState(thread, EntityState.Modified);
            Entities.SaveChanges();
        }

        public void SetThreadLastPostId(int threadId, int lastPostId)
        {
            Thread thread = GetThread(threadId);
            if (thread != null)
            {
                // update thread forum 
                thread.LastPostID = lastPostId;
            }
            Entities.SaveChanges(); 
        }

        public void SetThreadLastPostTime(int threadId, DateTime time)
        {
            Thread thread = GetThread(threadId);
            if (thread != null)
            {
                // update thread forum 
                thread.LastPostTime = time; 
            }
            Entities.SaveChanges();
        }
    }
}
